module RestBase
  class Application < Sinatra::Base
    def authenticated?
      authorized = true
      authorized = settings.authentication.authorized?(request, @env['HTTP_AUTHORIZATION']) unless settings.authentication.nil?
      authorized
    end
    
    def has_version?(version)
      return true unless settings.header_versioning
      @env['HTTP_ACCEPT'] = "*/*" if @env['HTTP_ACCEPT'].nil?
      @env['HTTP_ACCEPT'].include?(version)
    end

    def get_version
      matchdata = @env['HTTP_ACCEPT'].to_s.scan(/(version)=(\d*)/)
      matchdata[0][1].delete(',').to_f
    end

    def set_api_version
      @env['HTTP_ACCEPT'] += ";version=#{settings.api_version}" unless has_version?("version=")
      @env['sinatra.accept'] = nil
      @request_version = get_version
    end

    def set_request_body
      read_body = request.body.read

      begin
        if read_body.empty?
          @request_body = {}
        elsif request.media_type.downcase == 'text/xml'
          @request_body = Hash.from_xml(read_body)
          @request_body = Hash[@request_body.map{ |k, v| [k.to_sym, v] }]
          @request_body = @request_body[:request]
        else
          @request_body = JSON.parse(read_body, :symbolize_names => true)
        end
      rescue
        raise StandardError.new("Invalid Request Body")
      end
    end
    
    def setup_forensics
      @forensics = []
    end
    
    def add_forensics_to_response?
      !@env['Forensics'].nil? && @env['Forensics'].downcase == 'true'
    end
    
    def create_response()
      content_type :json
      content_type :xml if !request.accept?('*/*') && request.accept?('text/xml')
      
      if (response.status >= 400)
        error_hash = response.body
        error_hash = [error_hash] unless error_hash.is_a?(Array)

        response.body = nil
      end
      
      response_hash = { }
      response_hash[:errors] = error_hash unless error_hash.nil? || error_hash.empty?
      response_hash[:result] = response.body unless response.body.nil? || response.body.empty?
      response_hash[:forensics] = @forensics if add_forensics_to_response? && !(@forensics.nil? || @forensics.empty?)
      
      return '' if empty_body_status_code? && (response.body.empty?)
      return response_hash.to_xml(:root => :response) if response.headers['Content-Type'].start_with? 'application/xml;'
      response_hash.to_json
    end
    
    def empty_body_status_code?
      empty_body_status_codes = [201, 204, 304]
      response != nil && empty_body_status_codes.include?(response.status)
    end
  end
end